package org.ubc.cs410.disposal2020.server;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.ubc.cs410.disposal2020.BuildingBoundary;
import org.ubc.cs410.disposal2020.Map;
import org.ubc.cs410.disposal2020.PMF;
import org.ubc.cs410.disposal2020.client.dto.GeoPoint;

import com.Ostermiller.util.CSVParse;
import com.Ostermiller.util.CSVParser;
import com.Ostermiller.util.LabeledCSVParser;

public class DataPreloadServlet extends HttpServlet {

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		try {
			ServletFileUpload upload = new ServletFileUpload();
			response.setContentType("text/plain");

			String output = "";

			FileItemIterator iterator = upload.getItemIterator(request);
			while (iterator.hasNext()) {
				FileItemStream item = iterator.next();

				if (item.isFormField()) {
					//System.out.println("Got a form field: "
							//                + item.getFieldName());
				} else {
					/*System.out.println("Got an uploaded file: "
                                                        + item.getFieldName() + ", name = "
                                                        + item.getName());*/
					CSVParse csvParse = new CSVParser(item.openStream());
					LabeledCSVParser parser = new LabeledCSVParser(csvParse);
					Map map = convertString2Map(item.getName(), parser);
					PersistenceManager pm = PMF.get().getPersistenceManager();
					pm.makePersistent(map);
					pm.close();
				}
			}
		} catch (Exception ex) {
			throw new ServletException(ex);
		}
	}

	private static Map convertString2Map(String name, LabeledCSVParser parser)
	throws IOException {
		File file = new File(name);
		Map map = new Map(file.getName());
		java.util.Map<Integer, BuildingBoundary> buildingMap = new HashMap<Integer, BuildingBoundary>();
		String[] labels = parser.getLabels();
		while (parser.getLine() != null) {
			int nbid = Integer.parseInt(parser.getValueByLabel("Building ID"));
			BuildingBoundary bb = buildingMap.get(nbid);
			if (bb == null) {
				Float latitude = Float.valueOf(parser
						.getValueByLabel("Latitude"));
				Float longitude = Float.valueOf(parser
						.getValueByLabel("Longitude"));

				//System.out.print(latitude + "\n" + longitude + "\n");

				bb = new BuildingBoundary(nbid, latitude, longitude);
				buildingMap.put(nbid, bb);
			} else {
				bb.addLatitude(Float
						.valueOf(parser.getValueByLabel("Latitude")));
				bb.addLongitude(Float.valueOf(parser
						.getValueByLabel("Longitude")));
			}
		}
		Collection<BuildingBoundary> buildingList = buildingMap.values();
		map.setBuildings(new HashSet<BuildingBoundary>());
		for (BuildingBoundary building : buildingList) {	
			//Testing: 

			/*
                	for (int i = 0; i < building.getLatitudes().size(); i++) {
                		System.out.print(building.getBuildingId() + "    " + building.getLatitudes().get(i) + "    " + building.getLongitudes().get(i) + "\n");  
                	}
			 */


			map.getBuildings().add(building);
		}
		GeoPoint geoPoint = getCenter(buildingList);
		map.setCenterLatitude(geoPoint.getLatitude());
		map.setCenterLongitude(geoPoint.getLongitude());

		map.setZoomLevel( 15);
		System.out.println("Zoom Level: " + map.getZoomLevel());
		return map;
	}

	private static int getZoomLevel(Collection<BuildingBoundary> buildingList) {

		int width = 640;
		int height = 480;

		List<Float> latitudesList = new ArrayList<Float>();
		List<Float> longitudeList = new ArrayList<Float>();
		for (BuildingBoundary boundary : buildingList) {
			latitudesList.addAll(boundary.getLatitudes());
			longitudeList.addAll(boundary.getLongitudes());
		}

		Collections.sort(latitudesList);
		Collections.sort(longitudeList);
		Float minLat = latitudesList.get(0);
		Float maxLat = latitudesList.get(latitudesList.size() - 1);

		Float minLng = longitudeList.get(0);
		Float maxLng = longitudeList.get(longitudeList.size() - 1);

		double deltaLat = Math.abs(maxLat - minLat);
		double deltaLng = Math.abs(maxLng - minLng);
		if (deltaLat == 0 && deltaLng == 0) {
			return 4;
		}
		double centerLat = (double) Math.PI * (minLat + maxLat) / 360.0F;
		double C = 0.0000107288;

		int z0 = (int) Math
		.ceil(Math.log(deltaLat / (C * (double) height)) / 0.6931);
		int z1 = (int) Math.ceil(Math.log(deltaLng
				/ (C * (double) width * Math.cos(centerLat))) / 0.6931);
		return (z1 > z0) ? z1 : z0;
	}

	private static GeoPoint getCenter(Collection<BuildingBoundary> buildingList) {
		GeoPoint centerPoint = null;
		List<Float> latitudesList = new ArrayList<Float>();
		List<Float> longitudeList = new ArrayList<Float>();
		for (BuildingBoundary boundary : buildingList) {
			latitudesList.addAll(boundary.getLatitudes());
			longitudeList.addAll(boundary.getLongitudes());
		}

		Collections.sort(latitudesList);
		Collections.sort(longitudeList);
		Float minLat = latitudesList.get(0);
		Float maxLat = latitudesList.get(latitudesList.size() - 1);

		Float minLng = longitudeList.get(0);
		Float maxLng = longitudeList.get(longitudeList.size() - 1);

		centerPoint = new GeoPoint((minLat + maxLat) / 2F,
				(minLng + maxLng) / 2F);

		return centerPoint;
	}
}